PlanetScale のブランチ機能を試してみた
西田@CX事業本部です
今回はサーバーレスRDBの PlanetScale のブランチ機能を試してみました
ブランチ機能とは
Git のブランチのように、DBのスキーマのスナップショットを作成し、互いのブランチのスキーマに影響を出さずにを変更することができます
ブランチの種類
PlanetScale のブランチには2種類あります
ブランチ | 説明 |
---|---|
Development | 開発用 |
Production | 本番用 |
Production ブランチには Development ブランチに比べ以下の特徴があります
- 高い可用性
- プロダクションブランチのスキーマに対する直接的な変更を禁止し、デプロイリクエスト(後程説明)でのみ変更を可能とする(これはデフォルトの挙動で変更することは可能)
- 日時でバックアップ
※ Production ブランチを2つ以上作成するには執筆時点だと Scaler Plan 以上にする必要があります
デプロイリクエストとは
GitHubのPull Requestに相当する機能で、スキーマの変更をリクエストすることができます。開発チームのメンバーがデプロイリクエストのスキーマの差分を確認し、レビューを行い、必要に応じてコメントし、問題がなくなればProductionブランチに適用するといった Purll Request を使った開発フローと同じようなフローでデータベースのスキーマを管理することができます
今回のシナリオ
今回は、前回のブログの 続きで、前回作成したお問合せフォームに「製品名」を新しく入力できるようにします。この「製品名」を保持するためのスキーマ変更をブランチ機能を使ってデプロイリクエストで実施します
main ブランチをProductionブランチに変更
最初に、デフォルトで作成されている main
ブランチを Production ブランチに変更します
※ Production ブランチは main ブランチに限らず、どの Development ブランチからも Production ブランチにすること可能です。例えば stable
や release
ブランチを作成し、それらを Production ブランチにすることができます
main ブランチの画面を開くと、Production ブランチが存在しないという警告と一緒に、Development ブランチを Production ブランチに変更するためのボタンが表示されるので、これをクリックします
ダイアログが表示されるので、 main
ブランチを選択し、「Promote Branch」ボタンをクリックします
Development ブランチを作成
デプロイリクエストの元ブランチになる Developmentブランチを作成します。こちらのブランチに対しスキーマ変更を行い、機能追加が完了すれば、Productionブランチにデプロイリクエストを作成します
名前に今回の変更内容を表した名前を入力しブランチを作成します。元になるブランチはプロダクションブランチにした main
を選択し、mainブランチと同じ、東京リージョンを選択します
アプリケーションを修正
新しく作ったDevelopmentブランチにローカル環境から接続します
$ pscale connect test-branch add-product-name --port 3309
前回の続きなので .env
ファイルに以下の環境変数が設定されてる前提です。上記の接続を利用して Next.js が Development ブランチのデータベースに繋がることを想定してます
DATABASE_URL="mysql://root@127.0.0.1:3309/test-branch"
schema/schema.prisma
ファイルに必要な変更を加えます。今回は製品名を追加するので、 productName
というフィールドを追加します
@@ -16,4 +16,5 @@ model Inquiry { email String subject String message String + productName String }
Schemaの変更を PlanetScale のテーブル定義に反映します
npx prisma db push
PlanetScale のブランチの Schema タブで変更が反映されてることを確認します
※ ブランチ作成時にデータはコピーされないので、注意してください。データもコピーしたい場合は Team Plan 以上から利用できる Data Branching 機能が必要です
この時点で Production ブランチを確認すると、Development ブランチに対するスキーマ変更の影響がないことが確認できました
諸々修正し、製品名を登録できるようにします
参考までに、前回 からの差分を載せておきます
diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d89ef35..8ccab32 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -16,4 +16,5 @@ model Inquiry { email String subject String message String + productName String } \ No newline at end of file diff --git a/src/libs/database.ts b/src/libs/database.ts index 350eac5..12a5646 100644 --- a/src/libs/database.ts +++ b/src/libs/database.ts @@ -6,6 +6,7 @@ export type InquiryInput = { name: string, email: string, subject: string, + productName: string, message: string, } diff --git a/src/pages/api/inquiries/index.ts b/src/pages/api/inquiries/index.ts index 0f8e733..68fa241 100644 --- a/src/pages/api/inquiries/index.ts +++ b/src/pages/api/inquiries/index.ts @@ -9,6 +9,7 @@ const postInquiry = async (req: NextApiRequest, res: NextApiResponse) => { name: body.name, email: body.email, subject: body.subject, + productName: body.productName, message: body.message, }) diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 483e0c9..5f2130c 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -12,12 +12,14 @@ const Home: NextPage = () => { const [name, setName] = useState(""); const [email, setEmail] = useState(""); const [subject, setSubject] = useState(""); + const [productName, setProductName] = useState(""); const [message, setMessage] = useState(""); const clearForm = () => { setName(""); setEmail(""); setSubject(""); + setProductName(""); setMessage(""); } @@ -27,7 +29,7 @@ const Home: NextPage = () => { e.preventDefault(); const response = await fetch("/api/inquiries", {method: "POST", body: JSON.stringify({ - name, email, subject, message + name, email, subject, productName, message }), headers: { "Content-Type": "application/json" @@ -61,6 +63,12 @@ const Home: NextPage = () => { </label> <input onChange={(e) => setSubject(e.target.value)} type="text" value={subject} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700" /> </div> + <div className="mb-4"> + <label className="block text-gray-700 text-sm font-bold mb-1"> + ProductName + </label> + <input onChange={(e) => setProductName(e.target.value)} type="text" value={productName} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700" /> + </div> <div className="mb-4"> <label className="block text-gray-700 text-sm font-bold mb-1"> Message @@ -78,6 +86,7 @@ const Home: NextPage = () => { <th className="py-3 px-6">Email</th> <th className="py-3 px-6">Subject</th> <th className="py-3 px-6">Message</th> + <th className="py-3 px-6">ProductName</th> </tr> </thead> <tbody> @@ -87,6 +96,7 @@ const Home: NextPage = () => { <td className="py-4 px-6">{inquiry.name}</td> <td className="py-4 px-6">{inquiry.email}</td> <td className="py-4 px-6">{inquiry.subject}</td> + <td className="py-4 px-6">{inquiry.productName}</td> <td className="py-4 px-6">{inquiry.message}</td> </tr> )
デプロイリクエストを作成
PlanetScale のブランチ画面からデプロイリクエストを作成します
デプロイリクエストの画面で変更されたスキーマの差分が確認できます
コメントや、Approveもできます
デプロイリクエストをデプロイする
内容を確認できたら、デプロイリクエストをデプロイし、Production ブランチにスキーマ変更を反映します
執筆時にここで、追加された列にデフォルト値が設定されてないことでデプロイエラーが発生しました。 productName
にデフォルト値を設定して再度デプロイします。すでにデータが登録されているテーブルに列追加する際は、デフォルト値を設定するか、Not Null 制約を外す必要がありそうです
prisma/schema.prisma
productName String @default("") // デフォルト値を追加
変更をDevelopmentブランチに反映
npx prisma db push
エラーになったデプロイリクエストを完了させ、新しくデプロイリクエストを作成し、main ブランチにデプロイします
大体30秒ほどで完了しました
Vercel にアプリケーションの変更をデプロイ
最後にVercel にアプリケーションの変更をデプロイします
git push origin main
執筆時にprisma の client が再生成されていないことが原因で Vercel のデプロイが失敗してしまったのでpackage.json の postinstall
に prisma の client を再生成するコマンドを追加します
package.json
{ "scripts": { //... 省略 "postinstall": "prisma generate" } }
再度デプロイして変更が反映されてることを確認します
まとめ
今回は PlanetScale のブランチ機能を試してみました。ポピュラーな開発フローである Pull Request に似た感じで開発を進めていけるブランチ機能は、開発者にとって馴染みがあるので、使ってみると便利なのではないでしょうか
この記事が誰かの役に立てば幸いです